package mr.go.set.tests;

import static mr.go.set.tests.Helpers.counterGt10;
import static mr.go.set.tests.Helpers.increaseCountOfAllElementsByOne;
import static mr.go.set.tests.Helpers.never;
import static mr.go.set.tests.Helpers.startThreads;
import static mr.go.set.tests.Helpers.stopWhenExists;
import static mr.go.set.tests.Helpers.waitFor;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import mr.go.set.AggregatedSet;
import mr.go.set.ValueIterator;
import mr.go.set.samples.Counter;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class IteratorTestCase {

	private ExecutorService executor;

	private final int nThreads = 2;

	private AggregatedSet<String, Integer> set;

	private final String[] STRINGS = new String[] {
			"Two roads diverged in a yellow wood",
			"And sorry I could not travel both",
			"And be one traveler, long I stood",
			"And looked down one as far as I could",
			"To where it bent in the undergrowth;",
			"Then took the other, as just as fair",
			"And having perhaps the better claim",
			"Because it was grassy and wanted wear",
			"Though as for that the passing there",
			"Had worn them really about the same",

			"And both that morning equally lay",
			"In leaves no step had trodden black.",
			"Oh, I kept the first for another day!",
			"Yet knowing how way leads on to way",
			"I doubted if I should ever come back.",

			"I shall be telling this with a sigh",
			"Somewhere ages and ages hence:",
			"Two roads diverged in a wood, and I--",
			"I took the one less traveled by",
			"And that has made all the difference." };

	@Before
	public void setUp() throws Exception {
		set = new AggregatedSet<String, Integer>(new Counter());
		List<String> poem = Arrays.asList(STRINGS);
		set.addAll(poem);
		executor = Executors.newFixedThreadPool(nThreads);
	}

	@After
	public void tearDown() throws Exception {
		executor.shutdown();
	}

	@Test
	public final void testConsume() throws InterruptedException,
			ExecutionException {
		Future<?>[] futures = startThreads(executor, 2,
				increaseCountOfAllElementsByOne(set), stopWhenExists(set,
						counterGt10), never, null);
		ValueIterator<String, Integer> it = set.consume();
		int prevValue = 0;
		waitFor(futures);
		int size = set.size();
		int counter = 0;
		while (it.hasNext()) {
			counter++;
			String element = it.next();
			int value = it.value();
			assertTrue(value >= prevValue);
			assertFalse(set.contains(element));
			prevValue = value;
		}
		assertEquals(size, counter);
		assertTrue(set.size() == 0);
	}

	@Test
	public final void testRconsume() throws InterruptedException,
			ExecutionException {
		Future<?>[] futures = startThreads(executor, 2,
				increaseCountOfAllElementsByOne(set), stopWhenExists(set,
						counterGt10), never, null);
		ValueIterator<String, Integer> it = set.rconsume();
		int prevValue = Integer.MAX_VALUE;
		waitFor(futures);
		int size = set.size();
		int counter = 0;
		while (it.hasNext()) {
			counter++;
			String element = it.next();
			int value = it.value();
			assertTrue(value <= prevValue);
			assertFalse(set.contains(element));
			prevValue = value;
		}
		assertEquals(size, counter);
		assertTrue(set.size() == 0);
	}

}
